/*
 * Copyright (c) 2008, Takashi Ito
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the authors nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "tansu_internal.h"
#include <wx/wx.h>
#include "LcFrame.h"
#include "LcPanel.h"
#include "light.h"

class MyTimer : public wxTimer {
public:
    MyTimer(struct event_base *evbase) : wxTimer(), count(0), evbase(evbase) {}
    void Notify();
private:
    unsigned int count;
    struct event_base *evbase;
};

void MyTimer::Notify()
{
    //printf("Notify %u\n", count++);
    event_base_loop(evbase, EVLOOP_NONBLOCK);
}

class MyApp : public wxApp {
public:
    MyApp() : m_target(false) {}
    virtual ~MyApp() { destroy_binary_light(m_light); }
    bool OnInit();
    int OnExit();
    bool SetTarget(bool on);
    bool GetTarget() { return m_target; }
private:
    MyTimer *timer;
    struct binary_light *m_light;
    int m_target;
    LcFrame *m_frame;
    struct event_base *evbase;
};

IMPLEMENT_APP_NO_MAIN(MyApp)

bool MyApp::SetTarget(bool on)
{
    m_target = on;

    if (m_target) {
        m_frame->panel_light->SetColor(255, 255, 255);
        m_frame->list_ctrl_sv->SetItem(0, 1, _("1"));
        m_frame->list_ctrl_sv->SetItem(1, 1, _("1"));
    } else {
        m_frame->panel_light->SetColor(0, 0, 0);
        m_frame->list_ctrl_sv->SetItem(0, 1, _("0"));
        m_frame->list_ctrl_sv->SetItem(1, 1, _("0"));
    }

    return m_target;
}

static struct tdom_doc *xml_parse(const char *buff, int buffsize)
{
    struct tdom_parser *parser;
    struct tdom_doc *doc;

    if (buff == NULL || buffsize < 4) /* <a/> */
        return NULL;

    if ((parser = tdom_parser_new()) == NULL)
        return NULL;

    if (tdom_parser_parse(parser, buff, buffsize) != 1) {
        tdom_parser_delete(parser);
        return NULL;
    }

    doc = tdom_parser_get_doc(parser);
    tdom_parser_delete(parser);

    return doc;
}

static void soap_cb(struct evhttp_request *req,
                    struct tansu_device *device,
                    struct tansu_service *service,
                    const char *action,
                    void *arg)
{
    struct evbuffer *buffer;
    struct tdom_doc *result = NULL;
    struct tdom_doc *soap_req = NULL;
    MyApp *app = (MyApp *)arg;

    buffer = evbuffer_new();

    soap_req = xml_parse((char *)EVBUFFER_DATA((req->input_buffer)),
                         EVBUFFER_LENGTH((req->input_buffer)));
    if (soap_req == NULL)
        goto out;

    if (strcmp(action, "SetTarget") == 0) {
        const char *value = tdom_soap_get(soap_req, "NewTargetValue");
        if (value == NULL)
            goto out;
        if (strcmp(value, "1") == 0)
            app->SetTarget(true);
        else if (strcmp(value, "0") == 0)
            app->SetTarget(false);
        else
            goto out;
        result = tdom_soap_new("urn:schemas-upnp-org:service:SwitchPower:1",
                               "SetTargetResponse");
        tdom_soap_set(result, "NewTargetValue", value);
    } else if (strcmp(action, "GetTarget") == 0) {
        result = tdom_soap_new("urn:schemas-upnp-org:service:SwitchPower:1",
                               "GetTargetResponse");
        tdom_soap_set(result, "RetTargetValue", app->GetTarget() ? "1" : "0");
    } else if (strcmp(action, "GetStatus") == 0) {
        result = tdom_soap_new("urn:schemas-upnp-org:service:SwitchPower:1",
                               "GetStatusResponse");
        tdom_soap_set(result, "ResultStatus", app->GetTarget() ? "1" : "0");
    }

    tdom_doc_delete(soap_req);

    tdom_writer_write_all(buffer, result);
    evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=\"utf-8\"");
    evhttp_send_reply(req, HTTP_OK, "OK", buffer);

    evbuffer_free(buffer);
    tdom_doc_delete(result);

    return;

out:
    evbuffer_free(buffer);
    evhttp_send_error(req, 500, "Internal Server Error");
}

bool MyApp::OnInit()
{
    evbase = event_base_new();
    m_frame = new LcFrame(evbase, NULL, wxID_ANY, wxT("Lighting Control"));
    SetTopWindow(m_frame);
    m_frame->Show();
    timer = new MyTimer(evbase);
    timer->Start(100);

    m_light = create_binary_light(evbase, "sample/bl.xml", "sample/sps.xml",
                                  soap_cb, this);

    return true;
}

int MyApp::OnExit()
{
    timer->Stop();
    delete timer;
    event_base_free(evbase);
    return 0;
}

int main(int argc, char *argv[])
{
    return wxEntry(argc, argv);
}

